package belf.migrate.engine.ddl.view.sqlserver;

import belf.migrate.api.exception.APIErrorCode;
import belf.migrate.api.model.QualifiersModel;
import belf.migrate.api.table.schema.Catalog;
import belf.migrate.core.util.StringTool;
import belf.migrate.engine.ddl.BaseDDLConvert;
import belf.migrate.engine.ddl.helper.sqlserver.SqlServerAntlrBuilder;
import belf.migrate.engine.job.exception.ConvertViewException;
import belf.migrate.plugin.sqlserver.antlr.TSqlLexer;
import belf.migrate.plugin.sqlserver.antlr.TSqlParser;
import belf.migrate.plugin.sqlserver.antlr.TSqlParserBaseListener;
import belf.migrate.plugin.sqlserver.antlr.TSqlParserBaseVisitor;
import com.github.vertical_blank.sqlformatter.SqlFormatter;
import com.github.vertical_blank.sqlformatter.languages.Dialect;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.TerminalNode;

import java.util.List;

/**
 * 将
 */
public class SqlServer2DMViewConvert extends BaseDDLConvert {

    public SqlServer2DMViewConvert(String objectName, String sql, Catalog sourceCatalog, Catalog sinkCatalog,
                                   String schema, QualifiersModel qualifiersModel) {
        super(objectName, sql, sourceCatalog, sinkCatalog, schema, qualifiersModel);
    }

    @Override
    public String convert() {

        // 创建一个CharStream
        CharStream input = CharStreams.fromString(sql);

        // 使用MySqlLexer进行词法分析
        TSqlLexer lexer = new TSqlLexer(input);

        // 使用CommonTokenStream将词法分析器生成的词汇流传递给解析器
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        // 使用TSqlParser进行语法分析
        TSqlParser parser = new TSqlParser(tokens);

        // 从解析器中获取起始规则并进行解析
        ParseTree tree = parser.tsql_file();

        //遍历根节点
        SqlServerViewVisitor visitor = new SqlServerViewVisitor(this);
        visitor.visit(tree);
        return visitor.toDMViewDDL();
    }

    private class SqlServerViewVisitor extends TSqlParserBaseVisitor<String> {
        private String viewName;
        private TSqlParser.Query_specificationContext queryRoot;
        private BaseDDLConvert ddlConvert;

        public SqlServerViewVisitor(BaseDDLConvert ddlConvert) {
            this.ddlConvert = ddlConvert;
        }

        @Override
        public String visitCreate_view(TSqlParser.Create_viewContext ctx) {
            List<TSqlParser.Id_Context> ids = ctx.simple_name().id_();
            viewName = ids.get(ids.size() - 1).getText();
            viewName = StringTool.removeChars(viewName, "[]");
            viewName = getQualifiersModel().getLeftQuote()
                    + schema
                    + getQualifiersModel().getRightQuote()
                    + "."
                    + getQualifiersModel().getLeftQuote()
                    + viewName
                    + getQualifiersModel().getRightQuote();

            queryRoot = ctx.select_statement_standalone().select_statement().query_expression().query_specification();
            return visitChildren(ctx);
        }

        @Override
        public String visitXml_data_type_methods(TSqlParser.Xml_data_type_methodsContext ctx) {
            ddlConvert.addWarning(new ConvertViewException(APIErrorCode.CONVERT_SQLSERVER_DDL_ERROR,
                    ddlConvert.getTaskType() + "的DDL转化遇到不支持的xml类型转化:" + ctx.getText(),
                    ddlConvert.getSql(),
                    ctx.getText()));
            return visitChildren(ctx);
        }

        @Override
        public String visitNodes_method(TSqlParser.Nodes_methodContext ctx) {
            ddlConvert.addWarning(new ConvertViewException(APIErrorCode.CONVERT_SQLSERVER_DDL_ERROR,
                    ddlConvert.getTaskType() + "的DDL转化遇到不支持的xml节点引用:" + ctx.getText(),
                    ddlConvert.getSql(),
                    ctx.getText()));
            return visitChildren(ctx);
        }

        public String toDMViewDDL() {
            StringBuilder sb = new StringBuilder();
            sb.append("CREATE VIEW "); //注意：FORCE参数，可以无视物理表是否存在，直接创造视图
            sb.append(viewName);
            sb.append(" AS\n");
            SqlServerAntlrBuilder builder = new SqlServerAntlrBuilder(ddlConvert, sb, getQualifiersModel(), getSchema());
            SqlServerViewListener listener = new SqlServerViewListener(builder);
            ParseTreeWalker walker = new ParseTreeWalker();
            walker.walk(listener, queryRoot);
//            return SqlFormatter.of(Dialect.PlSql).format(sb.toString()); //达梦数据库的语法兼容Oracle
            return sb.toString();
        }
    }

    private class SqlServerViewListener extends TSqlParserBaseListener {
        private SqlServerAntlrBuilder builder;

        public SqlServerViewListener(SqlServerAntlrBuilder builder) {
            this.builder = builder;
        }

        /**
         * 替换sqlserver创建视图的SQL中的方括号，替换函数，给表名加上schema（如源端没有带schema）
         * @param node
         */
        @Override
        public void visitTerminal(TerminalNode node) {
            builder.output(node);
        }
    }
}
